#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>

#include <linux/platform_device.h>

static struct class *virdev_class;
static struct device *virmouse_device;

static char manufacturer_string[256];
static char product_string[256];

static ssize_t virmouse_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
	return 0;
}

#define DESCRIPTOR_STRING_ATTR(field, buffer)				\
static ssize_t								\
field ## _show(struct device *dev, struct device_attribute *attr,	\
		char *buf)						\
{									\
	return sprintf(buf, "%s\n", buffer);				\
}									\
static ssize_t								\
field ## _store(struct device *dev, struct device_attribute *attr,	\
		const char *buf, size_t size)				\
{									\
	if (size >= sizeof(buffer)) return -EINVAL;			\
	return strlcpy(buffer, buf, sizeof(buffer));			\
}									\
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);

DESCRIPTOR_STRING_ATTR(iManufacturer, manufacturer_string)
DESCRIPTOR_STRING_ATTR(iProduct, product_string)
static DEVICE_ATTR(vmevent, 0644, NULL, virmouse_write);

static struct device_attribute *virmouse_attributes[] = {
	&dev_attr_iManufacturer,
	&dev_attr_iProduct,
	&dev_attr_vmevent,
	NULL
};

static int __init virdev_init(void)
{
	struct device_attribute **attrs = virmouse_attributes;
	struct device_attribute *attr;
	int err;

	strncpy(manufacturer_string, "SLAM", sizeof(manufacturer_string) - 1);
	strncpy(product_string, "virdev", sizeof(product_string) - 1);

	virdev_class = class_create(THIS_MODULE, "slam_virdev");
	if (IS_ERR(virdev_class))
		return PTR_ERR(virdev_class);

	virmouse_device = device_create(virdev_class, NULL, MKDEV(0, 0), NULL, "virmouse");
	if (IS_ERR(virmouse_device))
		return PTR_ERR(virmouse_device);

	while ((attr = *attrs++)) {
		err = device_create_file(virmouse_device, attr);
		if (err) {
			device_destroy(virdev_class, virmouse_device->devt);
			return err;
		}
	}

	printk("Hello World!\n");
	return 0;
}

static void __exit virdev_exit(void)
{
	class_destroy(virdev_class);
	printk("Bye!\n");
	return;
}

module_init(virdev_init);
module_exit(virdev_exit);

MODULE_AUTHOR("xinu<guochongxin@qq.com>");
MODULE_DESCRIPTION("SLAM Virtual Device Driver Demo");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");
